﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web;
using Autofac;
using Autofac.Builder;
using Autofac.Integration.Mvc;
using Autofac.Core;
using Forest.Core.Caching;
using Forest.Core.Configuration;
using Forest.Core.Data;
using Forest.Core.Events;
using Forest.Core.Fakes;
using Forest.Core.Infrastructure;
using Forest.Core.Infrastructure.DependencyManagement;
using Forest.Data;
using Forest.Core;
using Forest.Cat.Domain.Services;
using Forest.Cat.Domain;
using Forest.Web.Framework.Mvc.Routes;
using Forest.Web.Framework.Themes;
using Forest.Web.Framework.UI;
using Forest.Cat.Domain.Configuration;
using Forest.Cat.Domain.Services.HomePages;
using Forest.Cat.Domain.Services.Jobseekers;
using Forest.Cat.Domain.Services.Authentication;
using Forest.Cat.Domain.Shared.Security;
using Forest.Cat.Domain.Services.WantAds;
using Forest.Cat.Domain.Services.JobHunting;
using Forest.Cat.Domain.Services.Rankings;
using Forest.Cat.Domain.Services.CoverLetters;
using Forest.Cat.Domain.Services.Compnaies;
using Forest.Cat.Domain.Services.Catalog;
using Forest.Cat.Domain.Services.Pictures;
using Forest.Cat.Domain.Services.Resumes;
using Forest.Cat.Domain.Services.Links;
using Forest.Cat.Domain.Services.Applications;
using Forest.Cat.Domain.Services.Messages;


namespace Forest.Web.Framework
{
    public class DependencyRegistrar : IDependencyRegistrar
    {
        public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder)
        {
            //HTTP context and other related stuff
            builder.Register(c =>
                //register FakeHttpContext when HttpContext is not available
                HttpContext.Current != null ?
                (new HttpContextWrapper(HttpContext.Current) as HttpContextBase) :
                (new FakeHttpContext("~/") as HttpContextBase))
                .As<HttpContextBase>()
                .InstancePerHttpRequest();
            builder.Register(c => c.Resolve<HttpContextBase>().Request)
                .As<HttpRequestBase>()
                .InstancePerHttpRequest();
            builder.Register(c => c.Resolve<HttpContextBase>().Response)
                .As<HttpResponseBase>()
                .InstancePerHttpRequest();
            builder.Register(c => c.Resolve<HttpContextBase>().Server)
                .As<HttpServerUtilityBase>()
                .InstancePerHttpRequest();
            builder.Register(c => c.Resolve<HttpContextBase>().Session)
                .As<HttpSessionStateBase>()
                .InstancePerHttpRequest();

            //web helper
            builder.RegisterType<WebHelper>().As<IWebHelper>().InstancePerHttpRequest();

            //controllers 注册控制器，否则控制器构造方法不认可
            builder.RegisterControllers(typeFinder.GetAssemblies().ToArray());

            //data layer
            var dataSettingsManager = new DataSettingsManager();
            var dataProviderSettings = dataSettingsManager.LoadSettings();
            builder.Register(c => dataSettingsManager.LoadSettings()).As<DataSettings>();
            builder.Register(x => new EfDataProviderManager(x.Resolve<DataSettings>())).As<BaseDataProviderManager>().InstancePerDependency();


            builder.Register(x => (IEfDataProvider)x.Resolve<BaseDataProviderManager>().LoadDataProvider()).As<IDataProvider>().InstancePerDependency();
            builder.Register(x => (IEfDataProvider)x.Resolve<BaseDataProviderManager>().LoadDataProvider()).As<IEfDataProvider>().InstancePerDependency();

            if (dataProviderSettings != null && dataProviderSettings.IsValid())
            {
                var efDataProviderManager = new EfDataProviderManager(dataSettingsManager.LoadSettings());
                var dataProvider = (IEfDataProvider)efDataProviderManager.LoadDataProvider();
                dataProvider.InitConnectionFactory();

                builder.Register<IDbContext>(c => new EfObjectContext(dataProviderSettings.DataConnectionString)).InstancePerHttpRequest();
            }
            else
            {
                builder.Register<IDbContext>(c => new EfObjectContext(dataSettingsManager.LoadSettings().DataConnectionString)).InstancePerHttpRequest();
            }


            builder.RegisterGeneric(typeof(EfRepository<>)).As(typeof(IRepository<>)).InstancePerHttpRequest();

            //plugins
            // builder.RegisterType<PluginFinder>().As<IPluginFinder>().InstancePerHttpRequest();

            //cache manager
            builder.RegisterType<MemoryCacheManager>().As<ICacheManager>().Named<ICacheManager>("nop_cache_static").SingleInstance();
            builder.RegisterType<PerRequestCacheManager>().As<ICacheManager>().Named<ICacheManager>("nop_cache_per_request").InstancePerHttpRequest();

            //work context
            builder.RegisterType<WorkContext>().As<IWorkContext>().InstancePerHttpRequest();

            //services
            builder.RegisterType<ResumeService>().As<IResumeService>().InstancePerHttpRequest();
            builder.RegisterType<HomePageService>().As<IHomePageService>().InstancePerHttpRequest();
            builder.RegisterType<PageTitleBuilder>().As<IPageTitleBuilder>().InstancePerHttpRequest();
            //builder.RegisterType<JobService>().As<IJobService>().InstancePerHttpRequest();
            builder.RegisterType<JobPostingService>().As<IJobPostingService>().InstancePerHttpRequest();
            builder.RegisterType<JobAlertService>().As<IJobAlertService>().InstancePerHttpRequest();
            builder.RegisterType<RankingService>().As<IRankingService>().InstancePerHttpRequest();
            builder.RegisterType<CoverLetterService>().As<ICoverLetterService>().InstancePerHttpRequest();
            builder.RegisterType<CompanyService>().As<ICompanyService>().InstancePerHttpRequest();
            builder.RegisterType<PictureService>().As<IPictureService>().InstancePerHttpRequest();
            builder.RegisterType<LinkService>().As<ILinkService>().InstancePerHttpRequest();
            builder.RegisterType<ApplicationService>().As<IApplicationService>().InstancePerHttpRequest();
            builder.RegisterType<SavedJobService>().As<ISavedJobService>().InstancePerHttpRequest();
            builder.RegisterType<SavedCompanyService>().As<ISavedCompanyService>().InstancePerHttpRequest();
            builder.RegisterType<NewsService>().As<INewsService>().InstancePerHttpRequest();
            builder.RegisterType<CatalogItemService>().As<ICatalogItemService>().InstancePerHttpRequest();
            builder.RegisterType<ReceivedMessageService>().As<IReceivedMessageService>().InstancePerHttpRequest();
            builder.RegisterType<GenerateNumberService>().As<IGenerateNumberService>().InstancePerHttpRequest();
            builder.RegisterType<LovService>().As<ILovService>()
              .WithParameter(ResolvedParameter.ForNamed<ICacheManager>("nop_cache_static"))
              .InstancePerHttpRequest();
            builder.RegisterType<JobseekerService>().As<IJobseekerService>().InstancePerHttpRequest();
            builder.RegisterType<JobseekerRegistrationService>().As<IJobseekerRegistrationService>().InstancePerHttpRequest();
            builder.RegisterType<WantAdService>().As<IWantAdService>().InstancePerHttpRequest();
            builder.RegisterType<ResumeService>().As<IResumeService>().InstancePerHttpRequest();
            builder.RegisterType<ShieldedCompanyService>().As<IShieldedCompanyService>().InstancePerHttpRequest();

            builder.RegisterType<EncryptionService>().As<IEncryptionService>().InstancePerHttpRequest();
            builder.RegisterType<FormsAuthenticationService>().As<IAuthenticationService>().InstancePerHttpRequest();
            builder.RegisterType<WorkExperienceService>().As<IWorkExperienceService>().InstancePerHttpRequest();
            builder.RegisterType<EducationService>().As<IEducationService>().InstancePerHttpRequest();
            builder.RegisterType<SkillService>().As<ISkillService>().InstancePerHttpRequest();
            builder.RegisterType<CertificationService>().As<ICertificationService>().InstancePerHttpRequest();
            builder.RegisterType<TrainingService>().As<ITrainingService>().InstancePerHttpRequest();
            builder.RegisterType<NewsService>().As<INewsService>().InstancePerHttpRequest();
            builder.RegisterType<JobPositionService>().As<IJobPositionService>().InstancePerHttpRequest();

            // 主题
            builder.RegisterType<ThemeProvider>().As<IThemeProvider>().InstancePerHttpRequest();
            builder.RegisterType<ThemeContext>().As<IThemeContext>().InstancePerHttpRequest();


            builder.RegisterType<RoutePublisher>().As<IRoutePublisher>().SingleInstance();



            builder.RegisterGeneric(typeof(ConfigurationProvider<>)).As(typeof(IConfigurationProvider<>));
            builder.RegisterSource(new SettingsSource());

            builder.RegisterType<SettingService>().As<ISettingService>()
              .WithParameter(ResolvedParameter.ForNamed<ICacheManager>("nop_cache_static"))
              .InstancePerHttpRequest();

            //builder.RegisterGeneric(typeof(ConfigurationProvider<>)).As(typeof(IConfigurationProvider<>));
            //builder.RegisterSource(new SettingsSource());

            //HTML Editor services
            //builder.RegisterType<NetAdvDirectoryService>().As<INetAdvDirectoryService>().InstancePerHttpRequest();
            //builder.RegisterType<NetAdvImageService>().As<INetAdvImageService>().InstancePerHttpRequest();


            //Register event consumers
            var consumers = typeFinder.FindClassesOfType(typeof(IConsumer<>)).ToList();
            foreach (var consumer in consumers)
            {
                builder.RegisterType(consumer)
                    .As(consumer.FindInterfaces((type, criteria) =>
                    {
                        var isMatch = type.IsGenericType && ((Type)criteria).IsAssignableFrom(type.GetGenericTypeDefinition());
                        return isMatch;
                    }, typeof(IConsumer<>)))
                    .InstancePerHttpRequest();
            }
            builder.RegisterType<EventPublisher>().As<IEventPublisher>().SingleInstance();
            builder.RegisterType<SubscriptionService>().As<ISubscriptionService>().SingleInstance();

        }

        public int Order
        {
            get { return 0; }
        }
    }

    public class SettingsSource : IRegistrationSource
    {
        static readonly MethodInfo BuildMethod = typeof(SettingsSource).GetMethod(
            "BuildRegistration",
            BindingFlags.Static | BindingFlags.NonPublic);

        public IEnumerable<IComponentRegistration> RegistrationsFor(
                Service service,
                Func<Service, IEnumerable<IComponentRegistration>> registrations)
        {
            var ts = service as TypedService;
            if (ts != null && typeof(ISettings).IsAssignableFrom(ts.ServiceType))
            {
                var buildMethod = BuildMethod.MakeGenericMethod(ts.ServiceType);
                yield return (IComponentRegistration)buildMethod.Invoke(null, null);
            }
        }

        static IComponentRegistration BuildRegistration<TSettings>() where TSettings : ISettings, new()
        {
            return RegistrationBuilder
                .ForDelegate((c, p) => c.Resolve<IConfigurationProvider<TSettings>>().Settings)
                .InstancePerHttpRequest()
                .CreateRegistration();
        }

        public bool IsAdapterForIndividualComponents { get { return false; } }
    }
}
